// GPS处理单元
package main

import (
	"errors"
	"fmt"
	"math"
	"server/src/common"
	"time"

	"server/src/gps"
	"server/src/protocol808"
)

// 处理单元
type Processor struct {
	isDebug bool
	gps     gps.GPS
	lat     float64
	lng     float64
	dbo     *DBOperation
	cfg     *Config
}

// 构造函数
func NewProcessor(dbo *DBOperation, cfg *Config) *Processor {
	p := Processor{dbo: dbo, cfg: cfg, isDebug: cfg.Debug}
	return &p
}

// 主执行函数
func (p *Processor) Run() {
	// 重置未更新的GPS数据
	p.dbo.UpdateNewRawDatas()

	// 处理GPS纪录类别 0200
	go TimerBirthWarmPress0200(p.dbo, p.cfg)

	//select {}
}

// 处理GPS纪录类别 0200
func (p *Processor) processBirthWarmPress0200() {
	var rawDates []RawDataT
	var err error

	zLog("处理GPS纪录类别 0200 start time::", time.Now().Format(common.Layout))
	rawDates, err = p.dbo.GetNewRawDatas()
	if err != nil {
		zLogError("读GPS原始数据时出错:", err.Error())
		return
	}
	zLog("读到", len(rawDates), "条GPS数据")
	if len(rawDates) > 0 {
		for _, v := range rawDates {
			go p.dbo.UpdateLastRawData(v.ID)
		}

		for k, v := range rawDates {
			zLog("start k::", k, " ID为::", v.ID.Hex(), "设备号::", v.Imei)
			p.processRoutine(k, &v)
			zLog("end k::", k, " ID为::", v.ID.Hex(), "设备号::", v.Imei)
		}
	}
}

func (p *Processor) processRoutine(k int, v *RawDataT) {
	if p.dbo.ReceiverStatus(v.Imei) != -2 {
		err := p.processOne(v)
		if err != nil {
			zLogError("处理第", k, "条数据，ID为 ", v.ID.Hex(), "，设备号为 ", v.Imei, "异常：", err.Error())
		}
	}

	p.dbo.RemoveLastRawData(v.ID)
}

// 处理单条纪录
func (p *Processor) processOne(data *RawDataT) error {
	res := protocol808.Request{}
	//经纬度不合法的GPS数据
	//data.Data = "7E02000032060422111855000600000180000000410000000000000000000000000000240304203517300114310100050100060203470801012B0400000000DD7E"
	err, header, body := res.Parse(data.Data)
	if err != nil {
		return err
	}
	if header.MessageType != protocol808.PTPosition {
		return errors.New("不是0200协议数据")
	}

	tp := protocol808.TerminalPosition{}
	tp.Set(body)

	//GPS是否有效
	invalidGPS := false

	//过滤不合法的GPS数据
	if math.Abs(float64(tp.Latitude)) < 0.01 || math.Abs(float64(tp.Longitude)) < 0.01 {
		//return errors.New(fmt.Sprintf("%s的GPS坐标数据无效，lat=%f，lng=%f", data.Imei, tp.Latitude, tp.Longitude))
		invalidGPS = true
	}

	//过滤掉时间不正确的数据
	now := time.Now()
	today := (now.Year()-2000)*10000 + int(now.Month())*100 + now.Day()
	if tp.Date-today > 1 {
		return errors.New(fmt.Sprintf("无效日期值：%d", tp.Date))
	}

	position := PositionsT{}
	position.RawId = data.ID
	position.Rid = header.TerminalId
	position.Date = tp.Date
	position.Time = tp.Time
	position.T = time.Now().Unix()
	position.TerminalStatus = tp.TerminalStatus
	position.AlarmMark = tp.AlarmMark
	position.PositionAddition = tp.PositionAddition

	if !invalidGPS {
		position.Latitude = tp.Latitude
		position.Longitude = tp.Longitude
		p.lat, p.lng = p.gps.TransformFromWGSToGCJ(float64(position.Latitude), float64(position.Longitude))
		position.GCJLatitude = float32(p.lat)
		position.GCJLongitude = float32(p.lng)
		p.lat, p.lng = p.gps.BDEncrypt(p.lat, p.lng)
		position.BDLatitude = float32(p.lat)
		position.BDLongitude = float32(p.lng)
		position.Speed = tp.Speed
		position.Height = tp.Height
		position.Direction = tp.Direction

		//南纬，标志为负
		if position.TerminalStatus.Latitude == 1 {
			position.Latitude = -position.Latitude
			position.GCJLatitude = -position.GCJLatitude
			position.BDLatitude = -position.BDLatitude
		}

		//西经，标志为负
		if position.TerminalStatus.Longtitude == 1 {
			position.Longitude = -position.Longitude
			position.GCJLongitude = -position.GCJLongitude
			position.BDLongitude = -position.BDLongitude
		}

		//保存到位置信息表
		go func() {
			dboErr := p.dbo.SavePositions(&position)
			if dboErr != nil {
				zLogError("保存positions时出错：", dboErr.Error(), "；数据：", position)
				//return dboErr
			}
		}()

		//保存轨迹日期，此处不能用协程保存
		p.dbo.SaveGpsDay(position.Rid, position.Date)
	}

	//更新最新状态表，此处不能用协程保存
	p.dbo.SaveNewGPSData(position.Rid, position.Date, position.Time, position.Latitude, position.Longitude,
		position.BDLatitude, position.BDLongitude, position.GCJLatitude, position.GCJLongitude, position.Speed,
		position.Height, position.Direction, position.PositionAddition.Voltage, position.TerminalStatus.ACC,
		position.PositionAddition.GSMSignalStrength, position.PositionAddition.GPSSatelliteCount,
		position.PositionAddition.PowerSource, position.PositionAddition.ModuleStatus)

	if invalidGPS {
		return errors.New(fmt.Sprintf("%s的GPS坐标数据无效，lat=%f，lng=%f", data.Imei, tp.Latitude, tp.Longitude))
	}

	return nil
}
